#ifndef __CSBUFPARSER_H__
#define __CSBUFPARSER_H__

#include <stdint.h>
#include <string>
#include <vector>
#include <stack>

// 数据类型定义，同时也是作为该数据的长度
const uint8_t buftype_unknow = 0;
const uint8_t buftype_bool = 1;
const uint8_t buftype_uint8 = 1;
const uint8_t buftype_uint16 = 2;
const uint8_t buftype_uint32 = 4;
const uint8_t buftype_uint64 = 8;
const uint8_t buftype_int8 = 1;
const uint8_t buftype_int16 = 2;
const uint8_t buftype_int32 = 4;
const uint8_t buftype_int64 = 8;
const uint8_t buftype_float = 4;
const uint8_t buftype_double = 8;
const uint8_t buftype_string_l = 253;	// 长字符串
const uint8_t buftype_string_s = 254;	// 特殊类型，它的数据段由 １位数据长度 + 数据　构成
const uint8_t buftype_string = 255;	// 特殊类型，它的数据段由 两位数据长度 + 数据 构成

// 数据解析器，get/set 顺序必须按钮数据序号pos从小到大来
class CsbufParser
{
public:
	CsbufParser();
	CsbufParser(const CsbufParser& buf);
	~CsbufParser();

	void setData(const CsbufParser& buf);
	void setData(const std::string& data);
	void setData(const char* data, unsigned int len);
	const std::string& getData()	{ return _data; }

	void clear();

	void setBool(bool d, uint8_t pos);

	void setUint8(uint8_t d, uint8_t pos);
	void setUint16(uint16_t d, uint8_t pos);
	void setUint32(uint32_t d, uint8_t pos);
	void setUint64(uint64_t d, uint8_t pos);

	void setInt8(int8_t d, uint8_t pos);
	void setInt16(int16_t d, uint8_t pos);
	void setInt32(int32_t d, uint8_t pos);
	void setInt64(int64_t d, uint8_t pos);

	void setFloat(float d, uint8_t pos);
	void setDouble(double d, uint8_t pos);

	// 只支持2^16大小的字符串
	void setString(const char* d, uint8_t pos);
	void setString(const char* d, size_t n, uint8_t pos);
	void setString(const std::string& d, uint8_t pos);

	// 数组，存储数组元素个数，数据类型由之后的设置具体值决定。为了能够正确的跳过数组区域，我们约定数组域内的所有值的 pos 都设置成 0
	void setArray(uint16_t d, uint8_t pos);

	// 消息结构体，它的长度无法预先确定，但我们需要知道他的长度来正确跳过及正确读取，所以这个函数必须与 endSetMessage 成对出现。
	void setMessage(uint8_t pos);
	void endSetMessage();


	// 获取数据
	bool getBool(uint8_t pos);

	uint8_t getUint8(uint8_t pos);
	uint16_t getUint16(uint8_t pos);
	uint32_t getUint32(uint8_t pos);
	uint64_t getUint64(uint8_t pos);

	int8_t getInt8(uint8_t pos);
	int16_t getInt16(uint8_t pos);
	int32_t getInt32(uint8_t pos);
	int64_t getInt64(uint8_t pos);

	float getFloat(uint8_t pos);
	double getDouble(uint8_t pos);

	std::string getString(uint8_t pos);

	// 获取数组的元素个数
	uint16_t getArray(uint8_t pos);

	// 获取消息的数据块大小，当调用这个函数之后就会进入获取子消息结构方式，只有调用相应的 endGetMessage 才会退出
	uint16_t getMessage(uint8_t pos);
	void endGetMessage();
protected:
	// 计算序号pos所在的游标位置，如果存在 pos 字段则返回 true
	bool _setCursorWithPos(uint8_t pos);

	bool _setValue(void* dest, size_t n, uint8_t pos);
	bool _setValue2(void* dest, size_t n, uint8_t pos);

	void _memcpy(void* dest, const void* src, size_t n, bool isEndian = true);

	void _append(const void* src, size_t n);

	/** 获取当前可用于填值的数据长度 */
	size_t _getSize();
protected:
	std::string			_data;
	size_t				_cursor;
	std::stack<uint32_t>	_posStack;	// 消息开始位置列表
};

#endif // CsbufParser_h__
